﻿using System;
using System.ComponentModel;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using GanagroLiteData;
using Csla.Validation;
using GeneralUtilities;

namespace GanagroLiteBO
{
    public class NotaBO : IEditableObject, INotifyPropertyChanged, IDataErrorInfo
    {
        private bool m_Editing;
        private short _tipoOperacion;
        private bool isNew = true;

        #region Properties
        public TiposOperacion TipoOperacion
        {
            get { return (TiposOperacion) _tipoOperacion; }
            set { _tipoOperacion = (short)value; }
        }

        private string _nota;
        public string Nota
        {
            get { return _nota; }
            set
            {
                if (_nota != value)
                {
                    _nota = value;
                    FirePropertyChangedNotification("Nota");
                }
            }
        }

        DateTime _fecha;
        public DateTime Fecha
        {
            get { return _fecha; }
            set
            {
                if (_fecha != value)
                {
                    _fecha = value.Date;
                    FirePropertyChangedNotification("Fecha");
                }
            }
        }

        private bool _alojo = false;
        public bool Alojo
        {
            get { return _alojo; }
            set
            {
                if (_alojo != value)
                {
                    _alojo = value;
                    FirePropertyChangedNotification("Alojo");
                }
            }

        }

        private Int32 _precio;
        public Int32 Precio
        {
            get { return _precio; }
            set
            {
                if (_precio != value)
                {
                    _precio = value;
                    FirePropertyChangedNotification("Precio");
                }
            }
        }

        #endregion

        #region Constructor

        public NotaBO(TiposOperacion tOp)
        {
            _tipoOperacion = (short) tOp;
            _fecha = DateTime.Now.AddDays(1);
            _nota = GetDefaultNota(tOp);
            AddBusinessRules();
        }

        private static string GetDefaultNota(TiposOperacion tOp)
        {
            string strNota = string.Empty;

            switch (tOp)
            {
                case TiposOperacion.Pesaje_Carne:
                    strNota = "Lote de control: {}";
                    break;
                case TiposOperacion.compra:
                    strNota = "Compra a {comprador}, Tpte:{valor} ";
                    break;
                case TiposOperacion.venta:
                    strNota = "Venta a {vendedor},  Dcto Fondo {}";
                    break;
                case TiposOperacion.Muerte:
                    strNota = "Sintomas muerte: {}";
                    break;
                default:
                    break;
            }

            return strNota;
        }

        public bool exists()
        {
            using (GlContext gContext = new GlContext())
            {
                return gContext.NOTAS.Any(p => p.FECHA == Fecha && p.OPERACION == _tipoOperacion);
            }
        }

        public void Cargar()
        {
            NOTA notaDO;
            using (GlContext gContext = new GlContext())
            {
                notaDO = gContext.NOTAS.FirstOrDefault(p => p.FECHA == Fecha && p.OPERACION == _tipoOperacion);
                if ( (notaDO == null ? 0 : notaDO.OPERACION) == 0)  //TODO: test this
                {
                    this.Nota = GetDefaultNota((TiposOperacion)_tipoOperacion);
                    isNew = true;
                }
                else
                {
                    isNew = false;
                    this.Nota = notaDO.TEXTO;
                }
            }
        }

        #endregion

        #region Methods
        public void Guardar()
        {
            NOTA notaDO;
            using (GlContext glContext = new GlContext())
            {
                if (glContext.NOTAS.Any(p => p.FECHA == Fecha && p.OPERACION == _tipoOperacion))
                {
                    notaDO = glContext.NOTAS.First(p => p.FECHA == Fecha && p.OPERACION == _tipoOperacion);
                    glContext.NOTAS.Attach(notaDO);
                    glContext.Entry(notaDO).State = System.Data.Entity.EntityState.Modified;
                }
                else
                {
                    notaDO = new NOTA();
                    notaDO.ID = glContext.NOTAS.Max(p => p.ID) + 1;
                    notaDO.FECHA = Fecha;
                    notaDO.OPERACION = _tipoOperacion;
                    glContext.NOTAS.Add(notaDO);
                }

                notaDO.TEXTO = Nota;
                glContext.SaveChanges();
            }

        }

        #endregion Methods

        #region Validaciones

        private ValidationRules _validationRules;
        public ValidationRules ValidationRules
        {
            get
            {
                if (_validationRules == null)
                    _validationRules = new ValidationRules(this);
                return _validationRules;
            }
        }

        public bool Isvalid()
        {
            return Isvalid(false);
        }

        public bool Isvalid(bool BypassCheck)
        {
            if (BypassCheck == false)
            {
                ValidationRules.CheckRules();
            }

            return ValidationRules.GetBrokenRules().ErrorCount == 0;
        }


        public string Warnings()
        {
            {
                return ValidationRules.GetBrokenRules().ToString(Csla.Validation.RuleSeverity.Warning); 
            }
        }

        private static bool FechaValida<T>(T target, Csla.Validation.RuleArgs e) where T : NotaBO
        {
            bool isvalid = true;

            e.Description = string.Empty;

            if (target.Fecha > DateTime.Now.Date)
            {
                e.Description = string.Format("La fecha de {0} no puede ser en el futuro", target.TipoOperacion.ToString());
                e.Severity = RuleSeverity.Error;
                return false;
            }

            if (target.Fecha < DateTime.Now.Date.AddDays( utilities.MaximoDiasOperacionValida * -1 ))
            {
                e.Description = string.Format("La fecha de {0} no puede ser anterior a {1} dias", target.TipoOperacion.ToString(), utilities.MaximoDiasOperacionValida);
                e.Severity = RuleSeverity.Error;
                return false;
            }

            using (GlContext glContext = new GlContext())
            {
                DateTime dt = glContext.OPERACIONES.Where(p => p.OPERACION == (short)target.TipoOperacion).Max(q => q.FECHA);

                if (target.Fecha < glContext.OPERACIONES.Where(p => p.OPERACION == (short)target.TipoOperacion).Max(q => q.FECHA))
                {
                    e.Description = string.Format("La fecha es anterior a ultima {0}", target.TipoOperacion.ToString());
                    e.Severity = RuleSeverity.Warning;
                    isvalid = false;
                }
            }

            return isvalid;
        }

        /// <summary>
        /// Precio Valido: Cuando la nota se refiere a una compra / venta, el precio debe estar dentro de ciertos rangos,
        /// que se guardan en la tabla de parametros
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="target"></param>
        /// <param name="e"></param>
        /// <returns></returns>
        public static bool PrecioValido<T>(T target, Csla.Validation.RuleArgs e) where T : NotaBO
        {
            bool isvalid = true;
            e.Description = string.Empty;

            try
            {
                if (target._tipoOperacion == (short)TiposOperacion.compra || target._tipoOperacion == (short)TiposOperacion.venta)
                {
                    if (target._alojo == false)
                    {
                        if (target._precio < Int32.Parse(utilities.GetParametro(Pars.PrecioKiloMinimo)) || target.Precio > Int32.Parse(utilities.GetParametro(Pars.PrecioKiloMaximo)))
                        {
                            e.Description = string.Format("Precio debe estar entre {0} y {1}", utilities.GetParametro(Pars.PrecioKiloMinimo), utilities.GetParametro(Pars.PrecioKiloMaximo));
                            return false;
                        }
                    }
                    else
                    {
                        if (target._precio < Int32.Parse(utilities.GetParametro(Pars.PrecioAlojoMinimo)) || target.Precio > Int32.Parse(utilities.GetParametro(Pars.PrecioAlojoMaximo)))
                        {
                            e.Description = string.Format("Precio debe estar entre {0} y {1}", utilities.GetParametro(Pars.PrecioAlojoMinimo), utilities.GetParametro(Pars.PrecioAlojoMaximo));
                            return false;
                        }
                    }
                }
            }
            catch (FormatException)
            {
                e.Description = "Invalid format exception";
                return false;
            }
            catch (ArgumentNullException)
            {
                e.Description = "Null Argument exception";
                return false;
            }

            return isvalid;

        }

        private void AddBusinessRules()
        {
            try
            {
                // TODO: When time allows, check if we can clear the static methods from NotaBO. For now I added an if statement in ValidaPeso
                //ValidationRules.ClearRules();
                ValidationRules.AddRule(new Csla.Validation.RuleHandler<NotaBO,RuleArgs>(FechaValida), "Fecha");
                if ((_tipoOperacion == (short)TiposOperacion.venta) || (_tipoOperacion == (short)TiposOperacion.compra))
                {
                    ValidationRules.AddRule(new Csla.Validation.RuleHandler<NotaBO, RuleArgs>(PrecioValido), "Precio");
                }
                ValidationRules.AddRule(new Csla.Validation.RuleHandler(CommonRules.StringRequired), "Nota");
            }
            catch (Exception ex)
            {
                throw (new Exception("AddBusinessRules: " + ex.Message, ex));
            }

        }

        #endregion

        #region INotifyPropertyChanged Implementation
        protected void FirePropertyChangedNotification(string propName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propName));
            }
            ValidationRules.CheckRules(propName);
        }

        public event PropertyChangedEventHandler PropertyChanged;
        #endregion

        #region IDataErrorInfo Members

        //				    private string m_Error = string.Empty;
        //				    private Hashtable m_PropErrors = new Hashtable();

        [Browsable(false)]
        public string Error
        {
            get
            {
                if (!ValidationRules.IsValid)
                {
                    return ValidationRules.GetBrokenRules().First().Description;
                }
                else
                { return String.Empty; }
            }
        }

        [Browsable(false)]
        public string this[string columnName]
        {
            get
            {
                string result = string.Empty;
                if (!ValidationRules.IsValid)
                {
                    BrokenRule rule = ValidationRules.GetBrokenRules().GetFirstBrokenRule(columnName);
                    if (rule != null)
                        result = rule.Description;
                }

                return result;
            }
        }
        #endregion

        #region IEditableObject Members

        public void BeginEdit()
        {
            //if (!m_Editing)
            //{
            //}

            m_Editing = true;
        }

        public void CancelEdit()
        {
            m_Editing = false;
        }

        public void EndEdit()
        {
            //if (m_Editing)
            //{
            //}

            m_Editing = false;
        }

        #endregion



    }
}
